package filenavigation

import (
	"context"
	"errors"
	"fmt"
	fileoperate2 "gitlab.local/TerraMaster/tos-modules/fileoperate"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/os/glog"
	"gitlab.local/DO-module/new-filemanage-module/src/constant"
	"gitlab.local/DO-module/new-filemanage-module/src/service/file_recently"
	"gitlab.local/DO-module/new-filemanage-module/src/service/file_share"
	"gitlab.local/TerraMaster/tos-modules/database/sqlitemodel"
	"gitlab.local/golibrary/utils"
)

// ShareFileData 分享文件信息
type ShareFileData struct {
	fileoperate2.FoldersInfo
	Title      string `json:"title"`       //标题
	CreateTime string `json:"create_time"` //创建时间
}

func (n *FileNav) preHandle(shareLink string) (*sqlitemodel.ShareConfig, error) {
	link, err := n.navigation.share.ParseShareLink(shareLink)
	if err != nil {
		return nil, gerror.Wrap(err, "Parse Link error")
	}
	atoi, err := strconv.Atoi(link.Get("id"))
	if err != nil {
		return nil, gerror.Wrap(err, "Get id error")
	}
	data, e := n.navigation.share.GetShareData(atoi)
	if e != nil {
		return nil, gerror.Wrap(e, "Get Share Data error")
	}
	return data, nil
}

// GetShareFileData 获取分享文件(夹)或分享文件夹下文件信息
func (n *FileNav) GetShareFileData(shareLink, pwd, path string, c context.Context) ([]ShareFileData, error) {
	sf := make([]ShareFileData, 0)
	data, err := n.preHandle(shareLink)
	if err != nil {
		return sf, gerror.Wrap(err, "Get Share Data")
	}
	if !n.navigation.share.VerifyPwd(data.Password, pwd) { //验证密码
		return sf, errors.New("wrong password")
	}

	folders := make([]fileoperate2.FoldersInfo, 0)

	//判断path是否为分享文件夹子路径
	if path != "" {
		//验证是否为子路径
		if !n.navigation.share.IsSubPath(data.PathsId, []string{path}) {
			return sf, errors.New("the subPath is wrong")
		}
		stat, err := os.Stat(path)
		if err != nil {
			return sf, gerror.Wrap(err, "GetShareFileData3")
		}
		if !stat.IsDir() {
			return sf, errors.New("not a folder")
		}
		getFolders, err := n.fOptGetter.GetFolders(path, 0, 0, "", false, false, "", false)
		if err == nil {
			folders = getFolders.Data
		}
	} else {
		var ids []int
		for _, v := range strings.Split(data.PathsId, ",") {
			i, err := strconv.Atoi(v)
			if err != nil {
				continue
			}
			ids = append(ids, i)
		}
		if len(ids) == 0 {
			return sf, nil
		}
		var paths []sqlitemodel.SharePath
		_ = n.dbGetter.DbGet().Where("id in ?", ids).Select("path").Find(&paths)
		for _, v := range paths {

			// 分享里面存的图片可能已经不存在
			if !utils.Exists(v.Path) {
				continue
			}

			p, err := n.fOptGetter.GetFolder(v.Path)
			if err != nil {
				return sf, errors.New("GetShareFileData5")
			}
			folders = append(folders, *p)
		}
	}

	for _, v := range folders {
		p, e := utils.SwitchShowName(v.Path)
		if e != nil {
			return sf, gerror.Wrap(e, "GetShareFileData6")
		}
		v.VolumePath = p
		var s ShareFileData
		s.FoldersInfo = v
		s.Title = data.Title
		s.CreateTime = data.CreateData.Format("2006-01-02 15:04:05")
		sf = append(sf, s)
	}

	return sf, nil
}

// DownloadShareFile 下载分享文件
// shareLink（ShareLink分享链接参数path=%s&user=%s&time=%s）
// src 下载文件绝对路径
// pwd 密码
func (n *FileNav) DownloadShareFile(c *gin.Context, shareLink string, src []string, pwd string) {
	link, err := n.navigation.share.ParseShareLink(shareLink)
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		glog.Error(err, "DownloadShareFile")
		return
	}

	conf := file_recently.RecentlyConf{
		Quantity:           20,
		Security:           false,
		Coding:             "UTF8",
		LogIn:              false,
		NoShowHiddenFolder: false,
	}
	coding := conf.Coding

	id, err := strconv.Atoi(link.Get("id"))
	if err != nil {
		c.String(http.StatusInternalServerError, "internal error")
		glog.Error(err, "DownloadShareFile1")
		return
	}
	data, e := n.navigation.share.GetShareData(id)
	if e != nil {
		c.String(http.StatusInternalServerError, "internal error")
		glog.Error(e, "DownloadShareFile1")
		return
	}
	ss := n.navigation.share.ShareStatus(data)
	//文件分享是否被关闭
	if ss.IsClose {
		c.String(http.StatusInternalServerError, "sharing closed")
		return
	}
	//文件路径是否允许下载
	if ss.IsDownload {
		c.String(http.StatusInternalServerError, "prohibit downloads")
		return
	}
	//是否开始
	if ss.IsStart {
		c.String(http.StatusInternalServerError, "not sharing time")
		return
	}
	//是否过期
	if ss.IsExpires {
		c.String(http.StatusInternalServerError, "share the overdue")
		return
	}
	//是否加密
	if ss.IsEncrypt && !n.navigation.share.VerifyPwd(data.Password, pwd) {
		c.String(http.StatusInternalServerError, "password authentication error")
		return
	}
	//判断子路径
	if !n.navigation.share.IsSubPath(data.PathsId, src) {
		c.String(http.StatusInternalServerError, fmt.Sprintf("this %s is not shared", src))
		return
	}
	//切换用户
	uName := link.Get("user")
	if e = utils.SwitchUserRight(uName); e != nil {
		c.String(http.StatusInternalServerError, "obtaining permission failed")
		return
	}
	//下载文件
	if e = utils.DownloadFile(c, src, coding); e != nil {
		c.String(http.StatusInternalServerError, "internal error")
		glog.Error(e, "DownloadShareFile3")
		return
	}
	_ = utils.SwitchUserRight()
	//下载次数+1
	_ = n.dbGetter.DbGet().Model(&sqlitemodel.ShareConfig{}).Where("id=?", data.Id).Update("download_count", data.DownloadCount+1).Error
}

func (n *FileNav) IsShare(userName string, tag string) bool {
	return n.navigation.share.IsShare(userName, tag)
}

func (n *FileNav) GetShareList(userName string, tag string, page, limit int) ([]file_share.ShareData, error) {
	return n.navigation.share.GetShareList(userName, tag, page, limit)
}

func (n *FileNav) AddShareFile(userName string, data file_share.ShareData) (*file_share.ShareData, error) {
	conf, err := n.navigation.Recently.GetRecentlyConf(userName)
	if err != nil {
		return nil, gerror.Wrap(err, "AddShareFile")
	}
	return n.navigation.share.AddShareFile(userName, conf.ShareDomain, data)
}

func (n *FileNav) DelShare(id int) error {
	return n.navigation.share.DelShare(id)
}

func (n *FileNav) VerifySharePwd(shareLink string, pwd string) (uint8, error) {
	return n.navigation.share.VerifySharePwd(shareLink, pwd)
}

func (n *FileNav) GetShareStatus(shareLink string) (*file_share.ShareStatus, error) {
	data, err := n.preHandle(shareLink)
	if err != nil {
		return nil, gerror.Wrap(err, "Get Share Data")
	}
	return n.navigation.share.ShareStatus(data), nil
}

func (n *FileNav) UploadShareFileVerify(shareLink string, pwd string) (string, error) {
	return n.navigation.share.UploadShareFileVerify(shareLink, pwd)
}

// IncreaseViewCount 增加浏览量,扣除可访问次数
func (n *FileNav) IncreaseViewCount(shareLink, pwd string) (bool, error) {
	unescape, err := url.PathUnescape(shareLink)
	if err != nil {
		return false, gerror.Wrap(err, "IncreaseViewCount")
	}
	return n.navigation.share.IncreaseViewCount(unescape, pwd)
}

func (n *FileNav) GetShareMsg(userName string, id int) (*file_share.ShareData, error) {
	return n.navigation.share.GetShareMsg(id, n.navigation.share.GetCustomDomain())
}

// AddShareLinkFileControl 添加分享链接中的分享文件(有权限控制)
func (n *FileNav) AddShareLinkFileControl(shareLink string, paths []string) error {
	shareLink, err := url.PathUnescape(shareLink)
	if err != nil {
		return gerror.Wrap(err, "AddOrDelShareLinkFile")
	}
	link, err := n.navigation.share.ParseShareLink(shareLink)
	if err != nil {
		return err
	}
	id, err := strconv.Atoi(link.Get("id"))
	if err != nil {
		return err
	}
	return n.navigation.share.AddShareLinkFileControl(id, paths)
}

// DelShareLinkFileControl 删除分享链接中的分享文件(有权限控制)
func (n *FileNav) DelShareLinkFileControl(shareLink string, paths []string) error {
	shareLink, err := url.PathUnescape(shareLink)
	if err != nil {
		return gerror.Wrap(err, "AddOrDelShareLinkFile")
	}
	link, err := n.navigation.share.ParseShareLink(shareLink)
	if err != nil {
		return err
	}
	id, err := strconv.Atoi(link.Get("id"))
	if err != nil {
		return err
	}
	return n.navigation.share.DelShareLinkFileControl(id, paths)
}

// AddShareLinkFile 添加分享链接中的分享文件
func (n *FileNav) AddShareLinkFile(id int, paths []string) error {
	return n.navigation.share.AddShareLinkFile(id, paths)
}

// DelShareLinkFile 删除分享链接中的分享文件
func (n *FileNav) DelShareLinkFile(id int, paths []string) error {
	return n.navigation.share.DelShareLinkFile(id, paths)
}

// EditShare 编辑分享配置
func (n *FileNav) EditShare(arg *file_share.EditShare) error {
	return n.navigation.share.EditShare(arg)
}

// SwitchCloseStatus 修改关闭状态
func (n *FileNav) SwitchCloseStatus(id int, status bool) error {
	return n.navigation.share.SwitchCloseStatus(id, status)
}

// GetShareDataMsg 获取某个分享链接的文件信息
func (n *FileNav) GetShareDataMsg(id int, username string) ([]fileoperate2.FoldersInfo, error) {
	fd := make([]fileoperate2.FoldersInfo, 0)
	file := make([]fileoperate2.FoldersInfo, 0)
	for _, v := range n.navigation.share.GetShareConfigPaths(id) {
		folder, err := n.fOptGetter.GetFolder(v)
		if err != nil {
			continue
		}
		//忽略隐藏文件和文件夹
		if strings.HasPrefix(folder.Name, constant.IgnoreFilePre) {
			continue
		}
		//替换路径s
		switchPath, e := utils.SwitchShowName(folder.Path)
		if e != nil {
			continue
		}
		folder.VolumePath = switchPath
		folder.IsCollect = n.IsCollectList(username, folder.Path) //是否收藏
		folder.IsShare = true                                     //是否分享
		//层级
		folder.Level = utils.FileLevel(folder.Path)
		if folder.FType == utils.Folder {
			fd = append(fd, *folder)
		} else {
			file = append(file, *folder)
		}
	}
	return append(fd, file...), nil
}

// VerifyShareMultimediaPlay 校验多媒体播放（用于分享功能）
func (n *FileNav) VerifyShareMultimediaPlay(shareLink, pwd, path string) error {
	unescape, err := url.PathUnescape(shareLink)
	if err != nil {
		return gerror.Wrap(err, "VerifyShareMultimediaPlay")
	}
	link, err := n.navigation.share.ParseShareLink(unescape)
	if err != nil {
		return gerror.Wrap(err, "VerifyShareMultimediaPlay1")
	}
	atoi, err := strconv.Atoi(link.Get("id"))
	if err != nil {
		return gerror.Wrap(err, "VerifyShareMultimediaPlay2")
	}
	data, e := n.navigation.share.GetShareData(atoi)
	if e != nil {
		return gerror.Wrap(e, "VerifyShareMultimediaPlay3")
	}
	if !n.navigation.share.VerifyPwd(data.Password, pwd) {
		return errors.New("wrong password")
	}
	if !n.navigation.share.IsSubPath(data.PathsId, []string{path}) {
		return errors.New("the subPath is wrong")
	}
	return nil
}
